/*
 * (C) Copyright 2001-2010
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <command.h>
#include <net.h>
#include <miiphy.h>
#include <phy.h>


void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
{
	char *end;
	int i;

	for (i = 0; i < 6; ++i) {
		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
		if (addr)
			addr = (*end) ? end + 1 : end;
	}
}

int eth_getenv_enetaddr(char *name, uchar *enetaddr)
{
	eth_parse_enetaddr(getenv(name), enetaddr);
	return is_valid_ether_addr(enetaddr);
}

int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
{
	char buf[20];

	sprintf(buf, "%pM", enetaddr);

	return setenv(name, buf);
}

int eth_getenv_enetaddr_by_index(const char *base_name, int index,
				 uchar *enetaddr)
{
	char enetvar[32];
	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
	return eth_getenv_enetaddr(enetvar, enetaddr);
}

static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
				 uchar *enetaddr)
{
	char enetvar[32];
	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
	return eth_setenv_enetaddr(enetvar, enetaddr);
}


static int eth_mac_skip(int index)
{
	char enetvar[15];
	char *skip_state;
	sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
	return ((skip_state = getenv(enetvar)) != NULL);
}

#ifdef CONFIG_RANDOM_MACADDR
void eth_random_enetaddr(uchar *enetaddr)
{
	uint32_t rval;

	srand(get_timer(0));

	rval = rand();
	enetaddr[0] = rval & 0xff;
	enetaddr[1] = (rval >> 8) & 0xff;
	enetaddr[2] = (rval >> 16) & 0xff;

	rval = rand();
	enetaddr[3] = rval & 0xff;
	enetaddr[4] = (rval >> 8) & 0xff;
	enetaddr[5] = (rval >> 16) & 0xff;

	/* make sure it's local and unicast */
	enetaddr[0] = (enetaddr[0] | 0x02) & ~0x01;
}
#endif

/*
 * CPU and board-specific Ethernet initializations.  Aliased function
 * signals caller to move on
 */
static int __def_eth_init(bd_t *bis)
{
	return -1;
}
int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));

#ifdef CONFIG_API
static struct {
	uchar data[PKTSIZE];
	int length;
} eth_rcv_bufs[PKTBUFSRX];

static unsigned int eth_rcv_current, eth_rcv_last;
#endif

static struct eth_device *eth_devices;
struct eth_device *eth_current;

struct eth_device *eth_get_dev_by_name(const char *devname)
{
	struct eth_device *dev, *target_dev;

	BUG_ON(devname == NULL);

	if (!eth_devices)
		return NULL;

	dev = eth_devices;
	target_dev = NULL;
	do {
		if (strcmp(devname, dev->name) == 0) {
			target_dev = dev;
			break;
		}
		dev = dev->next;
	} while (dev != eth_devices);

	return target_dev;
}

struct eth_device *eth_get_dev_by_index(int index)
{
	struct eth_device *dev, *target_dev;

	if (!eth_devices)
		return NULL;

	dev = eth_devices;
	target_dev = NULL;
	do {
		if (dev->index == index) {
			target_dev = dev;
			break;
		}
		dev = dev->next;
	} while (dev != eth_devices);

	return target_dev;
}

int eth_get_dev_index(void)
{
	if (!eth_current)
		return -1;

	return eth_current->index;
}

static void eth_current_changed(void)
{
	char *act = getenv("ethact");
	/* update current ethernet name */
	if (eth_current) {
		if (act == NULL || strcmp(act, eth_current->name) != 0)
			setenv("ethact", eth_current->name);
	}
	/*
	 * remove the variable completely if there is no active
	 * interface
	 */
	else if (act != NULL)
		setenv("ethact", NULL);
}

int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
		   int eth_number)
{
	unsigned char env_enetaddr[6];
	int ret = 0;

	eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);

	if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
		if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
				memcmp(dev->enetaddr, env_enetaddr, 6)) {
			printf("\nWarning: %s MAC addresses don't match:\n",
				dev->name);
			printf("Address in SROM is         %pM\n",
				dev->enetaddr);
			printf("Address in environment is  %pM\n",
				env_enetaddr);
		}

		memcpy(dev->enetaddr, env_enetaddr, 6);
	} else if (is_valid_ether_addr(dev->enetaddr)) {
		eth_setenv_enetaddr_by_index(base_name, eth_number,
					     dev->enetaddr);
		printf("\nWarning: %s using MAC address from net device\n",
			dev->name);
	}

	if (dev->write_hwaddr &&
			!eth_mac_skip(eth_number)) {
		if (!is_valid_ether_addr(dev->enetaddr))
			return -1;

		ret = dev->write_hwaddr(dev);
	}

	return ret;
}

int eth_register(struct eth_device *dev)
{
	struct eth_device *d;
	static int index;

	assert(strlen(dev->name) < sizeof(dev->name));

	if (!eth_devices) {
		eth_current = eth_devices = dev;
		eth_current_changed();
	} else {
		for (d = eth_devices; d->next != eth_devices; d = d->next)
			;
		d->next = dev;
	}

	dev->state = ETH_STATE_INIT;
	dev->next  = eth_devices;
	dev->index = index++;

	return 0;
}

int eth_unregister(struct eth_device *dev)
{
	struct eth_device *cur;

	/* No device */
	if (!eth_devices)
		return -1;

	for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
	     cur = cur->next)
		;

	/* Device not found */
	if (cur->next != dev)
		return -1;

	cur->next = dev->next;

	if (eth_devices == dev)
		eth_devices = dev->next == eth_devices ? NULL : dev->next;

	if (eth_current == dev) {
		eth_current = eth_devices;
		eth_current_changed();
	}

	return 0;
}

static void eth_env_init(bd_t *bis)
{
	const char *s;

	if ((s = getenv("bootfile")) != NULL)
		copy_filename(BootFile, s, sizeof(BootFile));
}

int eth_initialize(bd_t *bis)
{
	int num_devices = 0;
	eth_devices = NULL;
	eth_current = NULL;

	bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
	miiphy_init();
#endif

#ifdef CONFIG_PHYLIB
	phy_init();
#endif

	eth_env_init(bis);

	/*
	 * If board-specific initialization exists, call it.
	 * If not, call a CPU-specific one
	 */
	if (board_eth_init != __def_eth_init) {		
		if (board_eth_init(bis) < 0)
			printf("Board Net Initialization Failed\n");
	} else if (cpu_eth_init != __def_eth_init) {		
		if (cpu_eth_init(bis) < 0)
			printf("CPU Net Initialization Failed\n");
	} else
		printf("Net Initialization Skipped\n");

	if (!eth_devices) {
		puts("No ethernet found.\n");
		bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
	} else {
		struct eth_device *dev = eth_devices;
		char *ethprime = getenv("ethprime");

		bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
		do {
			if (dev->index)
				puts(", ");

			printf("%s", dev->name);

			if (ethprime && strcmp(dev->name, ethprime) == 0) {
				eth_current = dev;
				puts(" [PRIME]");
			}

			if (strchr(dev->name, ' '))
				puts("\nWarning: eth device name has a space!"
					"\n");

			if (eth_write_hwaddr(dev, "eth", dev->index))
				puts("\nWarning: failed to set MAC address\n");

			dev = dev->next;
			num_devices++;
		} while (dev != eth_devices);

		eth_current_changed();
		putc('\n');
	}

	return num_devices;
}

#ifdef CONFIG_MCAST_TFTP
/* Multicast.
 * mcast_addr: multicast ipaddr from which multicast Mac is made
 * join: 1=join, 0=leave.
 */
int eth_mcast_join(IPaddr_t mcast_ip, u8 join)
{
	u8 mcast_mac[6];
	if (!eth_current || !eth_current->mcast)
		return -1;
	mcast_mac[5] = htonl(mcast_ip) & 0xff;
	mcast_mac[4] = (htonl(mcast_ip)>>8) & 0xff;
	mcast_mac[3] = (htonl(mcast_ip)>>16) & 0x7f;
	mcast_mac[2] = 0x5e;
	mcast_mac[1] = 0x0;
	mcast_mac[0] = 0x1;
	return eth_current->mcast(eth_current, mcast_mac, join);
}

/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
 * and this is the ethernet-crc method needed for TSEC -- and perhaps
 * some other adapter -- hash tables
 */
#define CRCPOLY_LE 0xedb88320
u32 ether_crc(size_t len, unsigned char const *p)
{
	int i;
	u32 crc;
	crc = ~0;
	while (len--) {
		crc ^= *p++;
		for (i = 0; i < 8; i++)
			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
	}
	/* an reverse the bits, cuz of way they arrive -- last-first */
	crc = (crc >> 16) | (crc << 16);
	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
	crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
	crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
	crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
	return crc;
}

#endif


int eth_init(bd_t *bis)
{
	struct eth_device *old_current, *dev;

	if (!eth_current) {
		puts("No ethernet found.\n");
		return -1;
	}

	/* Sync environment with network devices */
	dev = eth_devices;
	do {
		uchar env_enetaddr[6];

		if (eth_getenv_enetaddr_by_index("eth", dev->index,
						 env_enetaddr))
			memcpy(dev->enetaddr, env_enetaddr, 6);

		dev = dev->next;
	} while (dev != eth_devices);

	old_current = eth_current;
	do {
		debug("Trying %s\n", eth_current->name);

		if (eth_current->init(eth_current, bis) >= 0) {
			eth_current->state = ETH_STATE_ACTIVE;

			return 0;
		}
		debug("FAIL\n");

		eth_try_another(0);
	} while (old_current != eth_current);

	return -1;
}

void eth_halt(void)
{
	if (!eth_current)
		return;

	eth_current->halt(eth_current);

	eth_current->state = ETH_STATE_PASSIVE;
}

int eth_send(void *packet, int length)
{
	if (!eth_current)
		return -1;

	return eth_current->send(eth_current, packet, length);
}

int eth_rx(void)
{
	if (!eth_current)
		return -1;

	return eth_current->recv(eth_current);
}

#ifdef CONFIG_API
static void eth_save_packet(void *packet, int length)
{
	char *p = packet;
	int i;

	if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
		return;

	if (PKTSIZE < length)
		return;

	for (i = 0; i < length; i++)
		eth_rcv_bufs[eth_rcv_last].data[i] = p[i];

	eth_rcv_bufs[eth_rcv_last].length = length;
	eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
}

int eth_receive(void *packet, int length)
{
	char *p = packet;
	void *pp = push_packet;
	int i;

	if (eth_rcv_current == eth_rcv_last) {
		push_packet = eth_save_packet;
		eth_rx();
		push_packet = pp;

		if (eth_rcv_current == eth_rcv_last)
			return -1;
	}

	length = min(eth_rcv_bufs[eth_rcv_current].length, length);

	for (i = 0; i < length; i++)
		p[i] = eth_rcv_bufs[eth_rcv_current].data[i];

	eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
	return length;
}
#endif /* CONFIG_API */

void eth_try_another(int first_restart)
{
	static struct eth_device *first_failed;
	char *ethrotate;

	/*
	 * Do not rotate between network interfaces when
	 * 'ethrotate' variable is set to 'no'.
	 */
	ethrotate = getenv("ethrotate");
	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
		return;

	if (!eth_current)
		return;

	if (first_restart)
		first_failed = eth_current;

	eth_current = eth_current->next;

	eth_current_changed();

	if (first_failed == eth_current)
		NetRestartWrap = 1;
}

void eth_set_current(void)
{
	static char *act;
	static int  env_changed_id;
	struct eth_device *old_current;
	int	env_id;

	if (!eth_current)	/* XXX no current */
		return;

	env_id = get_env_id();
	if ((act == NULL) || (env_changed_id != env_id)) {
		act = getenv("ethact");
		env_changed_id = env_id;
	}
	if (act != NULL) {
		old_current = eth_current;
		do {
			if (strcmp(eth_current->name, act) == 0)
				return;
			eth_current = eth_current->next;
		} while (old_current != eth_current);
	}

	eth_current_changed();
}

char *eth_get_name(void)
{
	return eth_current ? eth_current->name : "unknown";
}

/*---------------------------------------------------------------------*/
#define XGPIOPS_DATA_LSW_OFFSET  0x00000000U  /* Mask and Data Register LSW, WO */
#define XGPIOPS_DATA_MSW_OFFSET  0x00000004U  /* Mask and Data Register MSW, WO */
#define XGPIOPS_DATA_OFFSET	 0x00000040U  /* Data Register, RW */
#define XGPIOPS_DATA_RO_OFFSET	 0x00000060U  /* Data Register - Input, RO */
#define XGPIOPS_DIRM_OFFSET	 0x00000204U  /* Direction Mode Register, RW */
#define XGPIOPS_OUTEN_OFFSET	 0x00000208U  /* Output Enable Register, RW */
#define XGPIOPS_INTMASK_OFFSET	 0x0000020CU  /* Interrupt Mask Register, RO */
#define XGPIOPS_INTEN_OFFSET	 0x00000210U  /* Interrupt Enable Register, WO */
#define XGPIOPS_INTDIS_OFFSET	 0x00000214U  /* Interrupt Disable Register, WO*/
#define XGPIOPS_INTSTS_OFFSET	 0x00000218U  /* Interrupt Status Register, RO */
#define XGPIOPS_INTTYPE_OFFSET	 0x0000021CU  /* Interrupt Type Register, RW */
#define XGPIOPS_INTPOL_OFFSET	 0x00000220U  /* Interrupt Polarity Register, RW */
#define XGPIOPS_INTANY_OFFSET	 0x00000224U  /* Interrupt On Any Register, RW */


#define XGPIOPS_DATA_MASK_OFFSET 0x00000008U  /* Data/Mask Registers offset */
#define XGPIOPS_DATA_BANK_OFFSET 0x00000004U  /* Data Registers offset */
#define XGPIOPS_REG_MASK_OFFSET  0x00000040U  /* Registers offset */


/* For backwards compatibility */
#define XGPIOPS_BYPM_MASK_OFFSET	(u32)0x40

#define XGPIOPS_INTTYPE_BANK0_RESET  0xFFFFFFFFU
#define XGPIOPS_INTTYPE_BANK1_RESET  0x3FFFFFFFU
#define XGPIOPS_INTTYPE_BANK2_RESET  0xFFFFFFFFU
#define XGPIOPS_INTTYPE_BANK3_RESET  0xFFFFFFFFU

#define XGPIOPS_IRQ_TYPE_EDGE_RISING	0x00U  /**< Interrupt on Rising edge */
#define XGPIOPS_IRQ_TYPE_EDGE_FALLING	0x01U  /**< Interrupt Falling edge */
#define XGPIOPS_IRQ_TYPE_EDGE_BOTH	0x02U  /**< Interrupt on both edges */
#define XGPIOPS_IRQ_TYPE_LEVEL_HIGH	0x03U  /**< Interrupt on high level */
#define XGPIOPS_IRQ_TYPE_LEVEL_LOW	0x04U  /**< Interrupt on low level */
/*@}*/

#define XGPIOPS_BANK0			0x00U  /**< GPIO Bank 0 */
#define XGPIOPS_BANK1			0x01U  /**< GPIO Bank 1 */
#define XGPIOPS_BANK2			0x02U  /**< GPIO Bank 2 */
#define XGPIOPS_BANK3			0x03U  /**< GPIO Bank 3 */

#define XGPIOPS_MAX_BANKS		0x04U  /**< Max banks in a GPIO device */
#define XGPIOPS_BANK_MAX_PINS		(u32)32 /**< Max pins in a GPIO bank */

#define XGPIOPS_DEVICE_MAX_PIN_NUM	(u32)118 /*< Max pins in the GPIO device*/


#define XGpioPs_ReadReg(BaseAddr, RegOffset)		\
		(*(volatile u32 * )((BaseAddr) + (RegOffset)))


#define XGpioPs_WriteReg(BaseAddr, RegOffset, Data)	\
		*(volatile u32 *) ((BaseAddr) + RegOffset) = Data

#define LED_DELAY 	10000000
#define FLASH_RESET_GPIO 0x41220000
#define FLASH_RST_PERIOD 600000

#define FIFO_CFG_GPIO 0x41200000
#define FIFO_DONE_GPIO 0x41210000

#define GPIO_SRIO_LINK_BASEADDR 0x41230000

typedef void (*XGpioPs_Handler) (void *CallBackRef, u32 Bank, u32 Status);


typedef struct {
	u16 DeviceId;		/**< Unique ID of device */
	u32 BaseAddr;		/**< Register base address */
} XGpioPs_Config;


typedef struct {
	XGpioPs_Config GpioConfig;	/**< Device configuration */
	u32 IsReady;			/**< Device is initialized and ready */
	XGpioPs_Handler Handler;	/**< Status handlers for all banks */
	void *CallBackRef; 		/**< Callback ref for bank handlers */
} XGpioPs;


XGpioPs_Config XGpioPs_ConfigTable[] =
{
	{
		0,
		0xE000A000
	}
};

XGpioPs_Config *g_GpioConfig;

void XGpioPs_GetBankPin(u8 PinNumber, u8 *BankNumber, u8 *PinNumberInBank)
{
	/*
	 * This structure defines the mapping of the pin numbers to the banks when
	 * the driver APIs are used for working on the individual pins.
	 */
	u32 XGpioPsPinTable[] = {
		(u32)31, /* 0 - 31, Bank 0 */
		(u32)53, /* 32 - 53, Bank 1 */
		(u32)85, /* 54 - 85, Bank 2 */
		(u32)117 /* 86 - 117 Bank 3 */
	};
	*BankNumber = 0U;
	while (*BankNumber < 4U) {
		if (PinNumber <= XGpioPsPinTable[*BankNumber]) {
			break;
		}
		(*BankNumber)++;
    }
	if (*BankNumber == (u8)0) {
		*PinNumberInBank = PinNumber;
	} else {
		*PinNumberInBank = (u8)((u32)PinNumber %
					(XGpioPsPinTable[*BankNumber - (u8)1] + (u32)1));
	}
}


void XGpioPs_SetDirectionPin(XGpioPs *InstancePtr, u32 Pin, u32 Direction)
{
	u8 Bank;
	u8 PinNumber;
	u32 DirModeReg;

	/*
	 * Get the Bank number and Pin number within the bank.
	 */
	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	DirModeReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				      ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				      XGPIOPS_DIRM_OFFSET);

//	DirModeReg = XGpioPs_ReadReg(0xE000A244,0);


	if (Direction!=(u32)0) { /*  Output Direction */
		DirModeReg |= ((u32)1 << (u32)PinNumber);
	} else { /* Input Direction */
		DirModeReg &= ~ ((u32)1 << (u32)PinNumber);
	}


	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			 ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			 XGPIOPS_DIRM_OFFSET, DirModeReg);

//	XGpioPs_WriteReg(0xE000A244, 0,DirModeReg);
}


void XGpioPs_SetOutputEnablePin(XGpioPs *InstancePtr, u32 Pin, u32 OpEnable)
{
	u8 Bank;
	u8 PinNumber;
	u32 OpEnableReg;

	/*
	 * Get the Bank number and Pin number within the bank.
	 */
	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);


	OpEnableReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				       ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
				       XGPIOPS_OUTEN_OFFSET);

//	OpEnableReg = XGpioPs_ReadReg(0xE000A248,0);


	if (OpEnable != (u32)0) { /*  Enable Output Enable */
		OpEnableReg |= ((u32)1 << (u32)PinNumber);
	} else { /* Disable Output Enable */
		OpEnableReg &= ~ ((u32)1 << (u32)PinNumber);
	}
	

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_OUTEN_OFFSET, OpEnableReg);
//	XGpioPs_WriteReg(0xE000A248,0, OpEnableReg);
}


void XGpioPs_WritePin(XGpioPs *InstancePtr, u32 Pin, u32 Data)
{
	u32 RegOffset;
	u32 Value;
	u8 Bank;
	u8 PinNumber;
	u32 DataVar = Data;

	/*
	 * Get the Bank number and Pin number within the bank.
	 */
	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	if (PinNumber > 15U) {
		/*
		 * There are only 16 data bits in bit maskable register.
		 */
		PinNumber -= (u8)16;
		RegOffset = XGPIOPS_DATA_MSW_OFFSET;
	} else {
		RegOffset = XGPIOPS_DATA_LSW_OFFSET;
	}

	/*
	 * Get the 32 bit value to be written to the Mask/Data register where
	 * the upper 16 bits is the mask and lower 16 bits is the data.
	 */
	DataVar &= (u32)0x01;
	Value = ~((u32)1 << (PinNumber + 16U)) & ((DataVar << PinNumber) | 0xFFFF0000U);

	XGpioPs_WriteReg(InstancePtr->GpioConfig.BaseAddr,
			  ((u32)(Bank) * XGPIOPS_DATA_MASK_OFFSET) +
			  RegOffset, Value);
}

u32 XGpioPs_ReadPin(XGpioPs *InstancePtr, u32 Pin)
{
	u8 Bank;
	u8 PinNumber;

	/*
	 * Get the Bank number and Pin number within the bank.
	 */
	XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

	return (XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,
				 ((u32)(Bank) * XGPIOPS_DATA_BANK_OFFSET) +
				 XGPIOPS_DATA_RO_OFFSET) >> (u32)PinNumber) & (u32)1;

}

void mygpio_init()
{
	XGpioPs Gpio;
	u32 Delay;
	u32 Data;


	XGpioPs_WriteReg(FIFO_CFG_GPIO,
			  0x0, 0x00000000U);

	XGpioPs_WriteReg(FIFO_CFG_GPIO,
			  0x4, 0x00000000U);

	XGpioPs_WriteReg(FIFO_DONE_GPIO,
			  0x0, 0xFFFFFFFFU);

	
	printf("reset fifo through GPIO completed\n");


	g_GpioConfig = &XGpioPs_ConfigTable[0];

	//Initialize the GPIO device.

	Gpio.IsReady = 0U;
	Gpio.GpioConfig.BaseAddr = g_GpioConfig->BaseAddr;

	Gpio.GpioConfig.DeviceId = 0;

	/*
	 * By default, interrupts are not masked in GPIO. Disable
	 * interrupts for all pins in all the 4 banks.
	 */
	XGpioPs_WriteReg(Gpio.GpioConfig.BaseAddr,
			  XGPIOPS_INTDIS_OFFSET, 0xFFFFFFFFU);

	XGpioPs_WriteReg(Gpio.GpioConfig.BaseAddr,
			  ((u32)(1) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTDIS_OFFSET, 0xFFFFFFFFU);

	XGpioPs_WriteReg(Gpio.GpioConfig.BaseAddr,
			  ((u32)(2) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTDIS_OFFSET, 0xFFFFFFFFU);

	XGpioPs_WriteReg(Gpio.GpioConfig.BaseAddr,
			  ((u32)(3) * XGPIOPS_REG_MASK_OFFSET) +
			  XGPIOPS_INTDIS_OFFSET, 0xFFFFFFFFU);

	/*
	 * Indicate the component is now ready to use.
	 */
	Gpio.IsReady = 0x11111111U;

	//Initialize the GPIO device. end
	XGpioPs_SetDirectionPin(&Gpio, 51, 1);
	XGpioPs_SetDirectionPin(&Gpio, 50, 1);
	XGpioPs_SetDirectionPin(&Gpio, 49, 1);

	XGpioPs_SetOutputEnablePin(&Gpio, 51, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, 50, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, 49, 1);

	// MIO0
	XGpioPs_WritePin(&Gpio, 51, 0x1);
	XGpioPs_WritePin(&Gpio, 50, 0x1);
	XGpioPs_WritePin(&Gpio, 49, 0x1);
	for (Delay = 0; Delay < LED_DELAY/2; Delay++);

	Data = XGpioPs_ReadPin(&Gpio, 51);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 51 to 1 failed\n\r");
	}
	Data = XGpioPs_ReadPin(&Gpio, 50);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 50 to 1 failed\n\r");
	}
	Data = XGpioPs_ReadPin(&Gpio, 49);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 49 to 1 failed\n\r");
	}
	

	XGpioPs_WritePin(&Gpio, 51, 0x0);
	XGpioPs_WritePin(&Gpio, 50, 0x0);
	XGpioPs_WritePin(&Gpio, 49, 0x0);
	for (Delay = 0; Delay < LED_DELAY; Delay++);

	Data = XGpioPs_ReadPin(&Gpio, 51);
	if (Data != 0 ) {
		printf("XGpioPs_WritePin 51 to 0 failed\n\r");
	}
	Data = XGpioPs_ReadPin(&Gpio, 50);
	if (Data != 0 ) {
		printf("XGpioPs_WritePin 50 to 0 failed\n\r");
	}
	Data = XGpioPs_ReadPin(&Gpio, 49);
	if (Data != 0 ) {
		printf("XGpioPs_WritePin 49 to 0 failed\n\r");
	}
	


	XGpioPs_WritePin(&Gpio, 51, 0x1);
	XGpioPs_WritePin(&Gpio, 50, 0x1);
	XGpioPs_WritePin(&Gpio, 49, 0x1);

	for (Delay = 0; Delay < LED_DELAY; Delay++);

	Data = XGpioPs_ReadPin(&Gpio, 51);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 51 to 1 failed\n\r");
	}
	Data = XGpioPs_ReadPin(&Gpio, 50);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 50 to 1 failed\n\r");
	}
	Data = XGpioPs_ReadPin(&Gpio, 49);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 49 to 1 failed\n\r");
	}
	
	
	printf("reset phy through GPIO completed\n");



	XGpioPs_WriteReg(GPIO_SRIO_LINK_BASEADDR,0x4,0);
	XGpioPs_WriteReg(GPIO_SRIO_LINK_BASEADDR,0,0xffffffff);


	printf("reset srio through GPIO completed\n");
	
	XGpioPs_SetDirectionPin(&Gpio, 0, 1);
	XGpioPs_SetOutputEnablePin(&Gpio, 0, 1);

	XGpioPs_WritePin(&Gpio, 0, 0x1);
	for (Delay = 0; Delay < LED_DELAY/2; Delay++);
	Data = XGpioPs_ReadPin(&Gpio, 0);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 0 to 1 failed\n\r");
	}

	XGpioPs_WritePin(&Gpio, 0, 0x0);
	for (Delay = 0; Delay < LED_DELAY/2; Delay++);
	Data = XGpioPs_ReadPin(&Gpio, 0);
	if (Data != 0 ) {
		printf("XGpioPs_WritePin 0 to 0 failed\n\r");
	}

	XGpioPs_WritePin(&Gpio, 0, 0x1);
	for (Delay = 0; Delay < LED_DELAY/2; Delay++);
	Data = XGpioPs_ReadPin(&Gpio, 0);
	if (Data != 1 ) {
		printf("XGpioPs_WritePin 0 to 1 failed\n\r");
	}
	
	printf("reset 1848 through GPIO completed\n");


	XGpioPs_WriteReg(FLASH_RESET_GPIO,
			  0x4, 0x00000000U);
	
	XGpioPs_WriteReg(FLASH_RESET_GPIO,
			  0x0, 0xFFFFFFFFU);

	for (Delay = 0; Delay < FLASH_RST_PERIOD; Delay++);

	XGpioPs_WriteReg(FLASH_RESET_GPIO,
			  0x0, 0xFFFFFFFDU);

	for (Delay = 0; Delay < FLASH_RST_PERIOD; Delay++);

	XGpioPs_WriteReg(FLASH_RESET_GPIO,
			  0x0, 0xFFFFFFFFU);

	for (Delay = 0; Delay < 2*FLASH_RST_PERIOD; Delay++);

	printf("reset nor flash through GPIO completed\n");
}


